/**
 * @Description 
 * @Version 
 * @Author Dong
 * @Date 2021-03-08 14:05:39
 * @LastEditors Dong
 * @LastEditTime 2021-03-09 09:25:57
 * @FilePath \fed-e-task-04-06\code\work\src\app\app.component.ts
 */
// src\app\app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { from, fromEvent, Observable, of } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { todoAnimations, todosAnimations } from './animation';
import { AppState } from './store';
import { addTodo, deleteTodo, changeTodo, initTodos } from './store/actions/todo.actions';
import { Todo } from './store/reducers/todo.reducer';
import { selectTodos } from './store/selectors/todo.selectors';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styles: [],
  animations: [ todoAnimations, todosAnimations ]
})
export class AppComponent implements AfterViewInit {
  // 输入框
  @ViewChild('AddTodoInput') AddTodoInput!: ElementRef
  // 添加 todo 的点击按钮
  @ViewChild('AddTodoButton') AddTodoButton!: ElementRef
  // todo 列表
  todos: Observable<Todo[]>
  // todo 列表数量
  todoListNumber: number = 0

  constructor (private store: Store<AppState>) {
    // 从缓存中获取 todo 列表
    const todos = JSON.parse(window.localStorage.getItem("todos") || '[]')
    // 如果有则将 todos 都添加到 store 中
    if (todos.length) this.store.dispatch(initTodos({ todos }))
    // 从 store 中获取所有的 todos 
    this.todos = this.store.pipe(select(selectTodos))
    // this.todos 是 Observable 对象 可以订阅数据变化 
    this.todos.subscribe(todos => {
      // 在数据变化时同步缓存到本地
      window.localStorage.setItem('todos', JSON.stringify(todos))
      // 修改 todo 列表数量
      this.todoListNumber = todos.length
    })
  }
  
  // 视图初始化结束
  ngAfterViewInit () {
    // 将监听文本输入框键盘抬起事件作为数据流
    fromEvent<KeyboardEvent>(this.AddTodoInput.nativeElement, 'keyup')
      .pipe(
        // 筛选出回车键数据流
        filter(event => event.key === "Enter"),
        // 从事件数据流中获取文本内容作为数据流
        map(event => (<HTMLInputElement>event.target).value),
        // 去除文本的首尾空格
        map(value => value.trim()),
        // 将不为空的文本作为数据流
        filter(value => value !== '')
      )
      // 订阅事件
      .subscribe(value => {
        // 调用 action 并传递输入框的内容
        this.store.dispatch(addTodo({ value }))
        // 清空文本输入框
        this.AddTodoInput.nativeElement.value = ''
      })
    
    // 将监听添加 todo 按钮的点击事件作为数据流
    fromEvent<MouseEvent>(this.AddTodoButton.nativeElement, 'click')
      .pipe(
        // 获取输入框文本作为数据流
        map(() => this.AddTodoInput.nativeElement.value),
        // 去除文本的首尾空格
        map(value => value.trim()),
        // 将不为空的文本作为数据流
        filter(value => value !== '')
      )
      // 订阅事件
      .subscribe(value => {
        // 调用 action 并传递输入框的内容
        this.store.dispatch(addTodo({ value }))
        // 清空文本输入框
        this.AddTodoInput.nativeElement.value = ''
      })
  }

  // 删除 todo 接收 todo.id
  deleteTodo (id: string) {
    // 调用 action 并传递 todo.id
    this.store.dispatch(deleteTodo({ id }))
  }

  // 修改 todo.checked 值 接收标签与 id
  changeTodo (event: Event, id: string) {
    const target = event.target as HTMLInputElement
    // 获取 checked value
    const { checked, value } = target
    // 调用 action 并传递 todo.id todo.value todo.checked
    this.store.dispatch(changeTodo({ id, value, checked }))
  }
}
